#pragma once

#include <iostream>
#include <vector>
#include <map>
#include <variant>
#include <typeinfo>

using oemCmd = uint8_t;

#define TEMP_FAULT_LOG_PATH "/tmp/cper/cper.tmp"

#define CPER_LOG_DIR "/var/log/ras/"

#define PACKET_ID_OFFSET 0

#define SMBIOS_FILE_PATH "/var/lib/smbios/smbios2"
#define memoryDeviceType 17

// IPMB related variables.
constexpr uint8_t ipmbRetriesCount = 2;
constexpr uint8_t ipmbChannelMask = 0x03;
constexpr uint8_t oemIpmbNetfn = 0x30;
constexpr uint8_t oemIpmbLun = 0x1;
constexpr uint8_t oemIpmbCmd = 0xff;

static constexpr uint8_t separateLen = 2;

struct MemoryInfo
{
    uint8_t type;
    uint8_t length;
    uint16_t handle;
    uint16_t phyArrayHandle;
    uint16_t errInfoHandle;
    uint16_t totalWidth;
    uint16_t dataWidth;
    uint16_t size;
    uint8_t formFactor;
    uint8_t deviceSet;
    uint8_t deviceLocator;
    uint8_t bankLocator;
    uint8_t memoryType;
    uint16_t typeDetail;
    uint16_t speed;
    uint8_t manufacturer;
    uint8_t serialNum;
    uint8_t assetTag;
    uint8_t partNum;
    uint8_t attributes;
    uint32_t extendedSize;
    uint16_t confClockSpeed;
    uint16_t minimumVoltage;
    uint16_t maximumVoltage;
    uint16_t configuredVoltage;
    uint8_t memoryTechnology;
    uint16_t memoryOperatingModeCap;
    uint8_t firwareVersion;
    uint16_t modelManufId;
    uint16_t modelProdId;
    uint16_t memSubConManufId;
    uint16_t memSubConProdId;
    uint64_t nvSize;
    uint64_t volatileSize;
    uint64_t cacheSize;
    uint64_t logicalSize;
} __attribute__((packed));

struct MDRSMBIOSHeader
{
    uint8_t dirVer;
    uint8_t mdrType;
    uint32_t timestamp;
    uint32_t dataSize;
} __attribute__((packed));

#define MemoryBufCount 32
#define deviceLocatorBufSize 13
struct OemMemoryInfo
{
    uint8_t channel;
    uint16_t handle;
    char deviceLocator[deviceLocatorBufSize];
    uint64_t memorySize; // Unit: KB
};

// IPMI Discrete sensor DBUS path
#define ProcessorInventoryPath                                                 \
    "/xyz/openbmc_project/ras/processorSeverity/CPER_Processor"
#define MemoryInventoryPath                                                    \
    "/xyz/openbmc_project/ras/memorySeverity/CPER_Memory"
#define PCIeIventoryPath "/xyz/openbmc_project/ras/pcieSeverity/CPER_PCIe"

// replay counts occurred on the C2C or PCIe bus.
// dict[uint16,uint64]:
//     CPU Number and Port Number
//        [15:8]: CPU Number - The CPU that a PCIE bus belongs to
//        [7:0]: PortID - C2C or PCIe port Number
//     Count - C2C or PCIe link Nack counts.
using BusNackCountType = std::map<uint16_t, uint64_t>;

// An array of Physical Address,
// correctable or uncorrectable events Count tuples where:
// dict[uint16,struct[uint64,uint64]]:
//     Channel - Memory Channel Number
//     Physical Address - Correctable physical address
//     Count - Number of current address errors
using CeUeAddressType = std::map<uint16_t, std::tuple<uint64_t, uint64_t>>;

// Correctable or Uncorrectable error count statistics:
// dict[uint16,uint64]:
//     Var1: CPU Number or Memory Channel Number
//     Var2: Count of Correctable or Uncorrectable events detected.
using CeUeCountType = std::map<uint16_t, uint64_t>;

// Error data of pcie root
// dict[uint16,dict[uint16,array[byte]]]:
//     Var1: Die Number:
//     Var2: PortID - PCIe Bus Number
//     Var3: - struct PCIeErrorInfo
using PCIeRootInfoType =
    std::map<uint16_t, std::map<uint16_t, std::vector<uint8_t>>>;

struct PCIeErrorInfo
{
    uint8_t portType;
    int8_t slotNumber;
    uint16_t vendorID;
    uint16_t deviceID;
    uint32_t cePCIeErrorType;
    uint32_t uePCIeErrorType;
    uint32_t ruePCIeErrorType;
    uint32_t ceCount;
    uint32_t ueCount;
} __attribute__((packed));

using rasValue = std::variant<CeUeAddressType, CeUeCountType, PCIeRootInfoType>;

enum cpuType : uint8_t
{
    UNKNOWN_CPU = 0,
    PS23_TX16,
    PS23_TX32,
    PS23_TX64,
};

enum channelId : uint8_t
{
    CH0 = 0,
    CH1,
    CH2,
    CH3,
    CH4,
    CH5,
    CH6,
    CH7,
    CH8,
    CH9,
    CH10,
    CH11,
    CH12,
    CH13,
    CH14,
    CH15,
};

enum ddrPinId : uint8_t
{
    DIMM0 = 0,
    DIMM1,
    DIMM2,
    DIMM3,
    DIMM4,
    DIMM5,
    DIMM6,
    DIMM7,
    DIMM8,
    DIMM9,
    DIMM10,
    DIMM11,
    DIMM12,
    DIMM13,
    DIMM14,
    DIMM15,
};

enum packetID : uint8_t
{
    FIRST_PACKET = 0,
    LAST_PACKET = 0xFF,
};

enum sensorType : uint8_t
{
    PROCESSOR,
    MEMORY,
    PCIE,
};

enum severityCPER : uint8_t
{
    RECOVERABLE = 0,
    FATAL,
    CORRECTED,
    INFORMATIONAL,
};

enum handleParseArgs : uint8_t
{
    NO_PARAMETERS = 0,
    COMPARE_AND_LABEL_NEW_CPER = 1,
};

#define TEMP_CORE_BIST_MAP_PATH "/tmp/core_bist_map/bist.tmp"

namespace oem
{
    constexpr oemCmd cmdAddCommonPlatformErrorRecord = 0x30;
    constexpr oemCmd cmdAddProceeosrCoreBistMap = 0x31;
    constexpr oemCmd cmdReadCommonPlatformErrorRecord = 0x3F;
}
